///////////////////////////////////////////////////////////
///////////////// Have an itch? Scratch it! ///////////////
///////////////////////// SCRATCH /////////////////////////
/////////////////////  A MUD  Server   ////////////////////
///////////////////// By: Jared Devall ////////////////////
/////////////////////      Thanks:     ////////////////////
/////////////////////  DIKU/Merc/ROM   ////////////////////
///////////////////// Aetas/Deus Gang  ////////////////////
/////////////////////       Beej       ////////////////////
///////////////////////////////////////////////////////////

#include "definitions.h"
#include <list>
#include "commands.h"
#include "commandTable.h"
#include "character.h"
#include "world.h"
#include "stringutil.h"
#include "split.h"
#include "logs.h"
#include "timestamp.h"
#include "functions.h"

using namespace std;

// Command definitions for commands beginning with the letters T through Z
// (Keep in alphabetical order... it's MUCH easier)
CmdTake::CmdTake() {
	SetName( "take" );
	SetLevel( BUILDER );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdTake::Execute( Character* c, const string& args ) {
	std::string buf;
	std::string target_s;
	std::string object_s;
	Character* target = 0;
	Object* object = 0;
	std::list< Character* >::iterator c_it;
	std::list< Object* >::iterator o_it;

	split( args, object_s, target_s );

	if ( args.empty() || object_s.empty() || target_s.empty() ) {
		c->Send( "syntax: take <object> <target>\n\r" );
		return false;
	}

	if ( ( target = World::Instance().FindCharacter( target_s ) ) == NULL ) {
		c->Send( "They're not here.\n\r" );
		return false;
	}

	for ( o_it = target->getInventory().begin(); o_it != target->getInventory().end(); o_it++ ) {
		std::string o_name = (*o_it)->getKeywords();
		if ( o_name == object_s || str_prefix( object_s, o_name ) )
			object = (*o_it);
	}

	if ( object == 0 ) {
		c->Send( "They don't have that object.\n\r" );
		return false;
	}

	if ( target->getLevel() > c->getLevel() - 3 ) {
		c->Send( "You can't take anything from them.\n\r" );
		return false;
	}

	target->getInventory().remove( object );
	c->getInventory().push_front( object );

	buf = "You take ";
	buf << object->getShort() << " from " << target->getName() << ".\n\r";
	c->Send( buf );
	buf = c->getName();
	buf << " takes " << object->getShort() << " from you.\n\r";
	target->Send( buf );

	return true;
}

CmdTell::CmdTell( ) {
	SetName( "tell" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdTell::Execute( Character* c, const string &args ) {
	string name;
	string arg;
	string message;
	Character* target;

	split( args, name, arg );
	if ( ( target = World::Instance().FindCharacter( name ) ) == NULL ) {
		c->Send( "That target cannot be found.\n\r" );
		return false;
	}

	message << c->getName() << " tells you '{Y" << arg << "{x'\n\r";
	target->Send( message );
	target->setReply( c->getName() );
	message.erase();
	message << "You tell " << target->getName() << " '{Y" << arg << "{x'\n\r";
	c->Send( message );
	return true;
}

CmdTimers::CmdTimers() {
	SetName( "timers" );
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdTimers::Execute( Character* c, const string& args ) {
	std::string buf;
	std::string tmp;
	std::string when;
	int seconds = 0;
	int minutes = 0;
	int hours = 0;
	int days = 0;
	std::list< Timer* >::iterator it;
	time_t current;
	time( &current );

	// Show system time...
	buf << "System Time: " << Timestamp::Instance().GetDateTime() << "\n\r\n\r";

	// Show status of all scheduled timers...
	buf << "\t{!WScheduled Timers{x\n\r";
	for ( it = World::Instance().getTimers().begin(); it != World::Instance().getTimers().end(); it++ ) {
		// Calculate number of seconds, minutes, hours, days...
		seconds = minutes = hours = days = 0;
		when.clear();
		seconds = (int)((*it)->getWhen() - current);
		while ( seconds >= 60 ) {
			minutes++;
			seconds -= 60;
		}
		while ( minutes >= 60 ) {
			hours++;
			minutes -= 60;
		}
		while ( hours >= 24 ) {
			days++;
			hours -= 24;
		}
		if ( days > 0 )
			when << days << " days, ";
		if ( hours > 0 )
			when << hours << " hours, ";
		if ( minutes > 0 )
			when << minutes << " minutes, ";
		if ( days > 0 || hours > 0 || minutes > 0 )
			when << "and ";
		when << seconds << " seconds";
		buf << format( 15, (*it)->getName()+":", tmp ) << when << "\n\r";
	}

	c->Send( buf );

	return true;
}

CmdTitle::CmdTitle( ) {
	SetName( "title" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdTitle::Execute( Character* c, const string &args ) {
	std::string buf;

	c->SetTitle( args.c_str() );
	buf << "Title set to " << c->GetTitle() << "{x.\n\r";
	c->Send( buf );
	return true;
}

CmdUp::CmdUp() {
	SetName( "up" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdUp::Execute( Character* c, const std::string& args ) {
	std::string buf;
	std::string fromMessage;
	std::string toMessage;
	Exit* in = &( c->getRoom()->GetExit( UP ) );
	
	if ( !in->GetThere() ) {
		buf << "There is no exit that way.\n";
		c->Send( buf );
		return true;
	}
	else if ( in->GetDoor() && !in->GetOpen() ) {
		buf << "That door is closed.\n";
		c->Send( buf );
		return true;
	}
	else {
		Room* from = c->getRoom();
		Room* to = 0;
		if ( ( to = World::Instance().FindRoom( in->GetPoint() ) ) == NULL ) {
			c->Send( "You can't go there.\n\r" );
			std::string message = "Exit inconsistency: ";
			message << from->GetVnum() << " up to " << in->GetPoint();
			log( SERVER, message );
			return false;
		}

		fromMessage << c->getName() << " has left up.";
		toMessage << c->getName() << " has arrived from below.";

		from->Remove( c );
		sendToRoom( from, fromMessage );
		sendToRoom( to, toMessage );
		to->Add( c );
		from->Remove( c );
		c->setRoom( World::Instance().FindRoom( to->GetVnum() )->GetVnum() );
		CmdLook Command;
		Command.Execute( c, "auto_look: up" );
	}

	return true;
}

CmdWest::CmdWest() {
	SetName( "west" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdWest::Execute( Character* c, const std::string& args ) {
	std::string buf;
	std::string fromMessage;
	std::string toMessage;
	Exit* in = &( c->getRoom()->GetExit( WEST ) );
	
	if ( !in->GetThere() ) {
		buf << "There is no exit that way.\n";
		c->Send( buf );
		return true;
	}
	else if ( in->GetDoor() && !in->GetOpen() ) {
		buf << "That door is closed.\n";
		c->Send( buf );
		return true;
	}
	else {
		Room* from = c->getRoom();
		Room* to = 0;
		if ( ( to = World::Instance().FindRoom( in->GetPoint() ) ) == NULL ) {
			c->Send( "You can't go there.\n\r" );
			std::string message = "Exit inconsistency: ";
			message << from->GetVnum() << " west to " << in->GetPoint();
			log( SERVER, message );
			return false;
		}

		fromMessage << c->getName() << " has left to the west.";
		toMessage << c->getName() << " has arrived from the east.";

		from->Remove( c );
		sendToRoom( from, fromMessage );
		sendToRoom( to, toMessage );
		to->Add( c );
		c->setRoom( World::Instance().FindRoom( to->GetVnum() )->GetVnum() );
		CmdLook Command;
		Command.Execute( c, "auto_look: west" );
	}

	return true;
}

CmdWho::CmdWho( ) {
	SetName( "who" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdWho::Execute( Character* c, const string &args ) {
	string buf,countt;
	std::string level;   // Used for spaces()
	std::string useless; // Used for spaces()
	int count = 0;
	list< Character* >::iterator a_it;
	
	for ( a_it = World::Instance().getClist().begin(); a_it != World::Instance().getClist().end(); ++a_it, count++ ) {
		buf << " ";
		if ( c->getLevel() >= BUILDER ) {
			level.clear();
			level << c->getLevel();
			buf << "[{y" << (*a_it)->getLevel() << spaces( 3, level.c_str(), useless ) << "{x] ";
		}
		if ( (*a_it)->GetStatus() != CONNECTED )
			buf << "[ {mBUSY{x ] ";
		buf << (*a_it)->getName() << ' ' << (*a_it)->GetTitle() << "\n\r";
	}
	countt << count;
	if ( count > 1 )
	     buf.insert( 0, "-- " + countt + " Players --\n\r" );
	else
         buf.insert( 0, "-- " + countt + " Player --\n\r" );
	
	c->Send( buf );
	return true;
}

CmdWhos::CmdWhos() {
	SetName( "whos" );
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( false );
}

bool CmdWhos::Execute( Character* c, const string& args ) {
	string buf;
	list< Character* >::iterator it;
	buf << "\t\t-- Who/Sockets --\n\r";
	for ( it = World::Instance().getClist().begin(); it != World::Instance().getClist().end(); ++it ) {
		buf << (*it)->getName() << " " << (*it)->GetTitle() << "\n\t{C" << (*it)->GetSocket()->GetSocketIP() << "{x ({W" << (*it)->GetSocket()->GetDescriptor() << "{x)\n\r";
	}
	c->Send( buf );
	return true;
}
